package cn.wlinker.video.monitor.brand.hikversion.create;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.PageUtil;
import cn.wlinker.video.monitor.brand.hikversion.HikVisionAccessPlatformEnum;
import cn.wlinker.video.monitor.brand.hikversion.create.net.HCNetPtzControl;
import cn.wlinker.video.monitor.brand.hikversion.create.net.HCNetRealPlay;
import cn.wlinker.video.monitor.brand.hikversion.create.net.config.NetConfig;
import cn.wlinker.video.monitor.brand.hikversion.create.net.enums.HCPlayControlEnum;
import cn.wlinker.video.monitor.brand.hikversion.create.net.enums.HCPresetControlEnum;
import cn.wlinker.video.monitor.brand.hikversion.utils.NetDeviceCacheUtils;
import cn.wlinker.video.monitor.constant.CommonConstant;
import cn.wlinker.video.monitor.domain.Page;
import cn.wlinker.video.monitor.domain.PageQuery;
import cn.wlinker.video.monitor.domain.dto.MonitorDeviceDTO;
import cn.wlinker.video.monitor.domain.dto.PlayUrlDTO;
import cn.wlinker.video.monitor.domain.vo.MonitorDeviceVO;
import cn.wlinker.video.monitor.domain.vo.PictureUrlVO;
import cn.wlinker.video.monitor.domain.vo.PresetAddVO;
import cn.wlinker.video.monitor.domain.vo.VideoVO;
import cn.wlinker.video.monitor.enums.FileTypeEnum;
import cn.wlinker.video.monitor.enums.MonitorDeviceStatusEnum;
import cn.wlinker.video.monitor.enums.VideoBrandEnum;
import cn.wlinker.video.monitor.service.IVideoStreamService;
import cn.wlinker.video.monitor.utils.FilePathUtils;
import cn.wlinker.video.monitor.utils.ServerUrlGenerator;
import cn.wlinker.video.monitor.utils.StreamUrlCacheUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * net设备构建视频流
 *
 * @author gxsjx
 * @version 1.0
 * @date 2022/11/21
 */
@Service
public class NetStreamServiceImpl implements IVideoStreamService {

    @Resource
    private ServerUrlGenerator serverUrlGenerator;

    @Override
    public PresetAddVO presetAdd(MonitorDeviceDTO monitorDeviceDTO, Integer index) {
        HCNetPtzControl.build(NetDeviceCacheUtils.getHcNetTools(monitorDeviceDTO), monitorDeviceDTO)
                .presetControl(HCPresetControlEnum.set, index);
        PresetAddVO presetAddVO = new PresetAddVO();
        presetAddVO.setIndex(index);
        return presetAddVO;
    }

    @Override
    public Boolean presetMove(MonitorDeviceDTO monitorDeviceDTO, Integer index) {
        return HCNetPtzControl.build(NetDeviceCacheUtils.getHcNetTools(monitorDeviceDTO), monitorDeviceDTO)
                .presetControl(HCPresetControlEnum.move, index);
    }

    @Override
    public Boolean presetClear(MonitorDeviceDTO monitorDeviceDTO, Integer index) {
        return HCNetPtzControl.build(NetDeviceCacheUtils.getHcNetTools(monitorDeviceDTO), monitorDeviceDTO)
                .presetControl(HCPresetControlEnum.clear, index);
    }

    @Override
    public Boolean ptzStart(MonitorDeviceDTO monitorDeviceDTO, Integer direction, Integer speed) {
        Optional<HCPlayControlEnum> byValue = HCPlayControlEnum.getByValue(direction);
        Assert.isTrue(byValue.isPresent(), "操作命令不合法");
        return HCNetPtzControl.build(NetDeviceCacheUtils.getHcNetTools(monitorDeviceDTO), monitorDeviceDTO)
                .ptzStart(byValue.get(), CommonConstant.SINGLE_MOVEMENT_TIME);
    }

    @Override
    public Boolean ptzStop(MonitorDeviceDTO monitorDeviceDTO, Integer direction) {
        Optional<HCPlayControlEnum> byValue = HCPlayControlEnum.getByValue(direction);
        Assert.isTrue(byValue.isPresent(), "操作命令不合法");
        return HCNetPtzControl.build(NetDeviceCacheUtils.getHcNetTools(monitorDeviceDTO), monitorDeviceDTO)
                .ptzStop(byValue.get());
    }

    @Override
    public VideoVO getRelayUrl(MonitorDeviceDTO dto, PlayUrlDTO playUrlDTO) {
        NetConfig netConfig = NetDeviceCacheUtils.getNetConfig(dto.getDeviceCode());
        String host = netConfig.getHost();
        String username = netConfig.getUsername();
        String password = netConfig.getPassword();
        DateTime startTime = DateUtil.parse(playUrlDTO.getStartTime());
        DateTime endTime = DateUtil.parse(playUrlDTO.getStopTime());
        Integer channelNo = dto.getChannelNo();
        String replayUrl = VideoBrandEnum.hk.getReplayUrl(host, username, password, channelNo, startTime, endTime);
        String streamId = StreamUrlCacheUtils.putAndReturnStreamId(host, channelNo, startTime, endTime, replayUrl);
        String videoUrl = serverUrlGenerator.getVideoUrl(streamId);
        return VideoVO.build(dto, videoUrl);
    }

    void checkDeviceStatus(MonitorDeviceDTO dto) {
        Map<Integer, Pair<String, Boolean>> ipChannelInfo = NetDeviceCacheUtils.getHcNetTools(dto).getIPChannelInfo();
        Pair<String, Boolean> stringBooleanPair = ipChannelInfo.get(dto.getChannelNo());
        Assert.notNull(stringBooleanPair, "设备不存在");
        Assert.isTrue(stringBooleanPair.getValue(), "设备不在线");
    }

    @Override
    public VideoVO buildVideoStream(MonitorDeviceDTO dto, PlayUrlDTO playUrlDTO) {
        //checkDeviceStatus(dto);
        NetConfig netConfig = NetDeviceCacheUtils.getNetConfig(dto);
        String host = netConfig.getHost();
        String username = netConfig.getUsername();
        String password = netConfig.getPassword();
        Integer channelNo = dto.getChannelNo();
        String h264Url = VideoBrandEnum.hk.getH264Url(host, username, password, channelNo);
        String streamId = StreamUrlCacheUtils.putAndReturnStreamId(host, channelNo, h264Url);
        String videoUrl = serverUrlGenerator.getVideoUrl(streamId);
        return VideoVO.build(dto, videoUrl);
    }

    @Override
    public PictureUrlVO capture(MonitorDeviceDTO dto, Integer quality) {
        //checkDeviceStatus(dto);
        String randomImgPath = FilePathUtils.getRandomNameWithPath(FileTypeEnum.jpg);
        int lUserID = NetDeviceCacheUtils.getHcNetTools(dto).getLUserID();
        Boolean capture = HCNetRealPlay.realPlayAndSavePic(lUserID, dto.getChannelNo(), randomImgPath);
        Assert.isTrue(capture, "抓图失败");
        PictureUrlVO pictureUrlVO = new PictureUrlVO();
        pictureUrlVO.setPicUrl(FilePathUtils.getUrlPathByFileName(randomImgPath));
        return pictureUrlVO;
    }

    @Override
    public Page<MonitorDeviceVO> getMonitorDeviceList(String deviceCode, String status, PageQuery pageQuery) {
        Map<Integer, Pair<String, Boolean>> ipChannelInfo = NetDeviceCacheUtils.getHcNetTools(deviceCode).getIPChannelInfo();
        List<MonitorDeviceVO> monitorDeviceVOList = new LinkedList<>();
        for (Integer channelNo : ipChannelInfo.keySet()) {
            Pair<String, Boolean> pair = ipChannelInfo.get(channelNo);
            MonitorDeviceVO monitorDeviceVO = getMonitorDeviceVO(deviceCode, channelNo, pair);
            monitorDeviceVOList.add(monitorDeviceVO);
        }
        Integer pageSize = pageQuery.getPageSize();
        int pageNum = pageQuery.getPageNum() - 1;
        int start = PageUtil.getStart(pageNum, pageSize);
        int end = PageUtil.getEnd(pageNum, pageSize);
        int count = monitorDeviceVOList.size();
        start = Math.min(start, count);
        end = Math.min(end, count);
        List<MonitorDeviceVO> records = monitorDeviceVOList.subList(start, end);
        Page<MonitorDeviceVO> voPage = new Page<>(pageNum, pageSize, count);
        voPage.setRecords(records);
        return voPage;
    }

    private static MonitorDeviceVO getMonitorDeviceVO(String deviceCode, Integer channelNo, Pair<String, Boolean> pair) {
        MonitorDeviceVO monitorDeviceVO = new MonitorDeviceVO();
        HikVisionAccessPlatformEnum accessPlatformEnum = HikVisionAccessPlatformEnum.net;
        monitorDeviceVO.setMonitorType(accessPlatformEnum.getVideoBrandEnum().getMonitorType());
        monitorDeviceVO.setAccessPlatform(accessPlatformEnum.getAccessPlatform());
        monitorDeviceVO.setDeviceCode(deviceCode);
        monitorDeviceVO.setChannelNo(channelNo);
        if (pair.getValue()) {
            monitorDeviceVO.setStatus(MonitorDeviceStatusEnum.online.getStatus());
            monitorDeviceVO.setIp(pair.getKey());
        } else {
            monitorDeviceVO.setStatus(MonitorDeviceStatusEnum.offline.getStatus());
        }
        return monitorDeviceVO;
    }


}
